import { Injectable } from '@nestjs/common';
import { and, eq, inArray, sql, like, or } from 'drizzle-orm';
import { DrizzleService } from '../../db/drizzle.service';
import { roles, roleMenus, roleDepts, userRoles, rolePermissions } from '../../db/schema';
import { QueryRoleDto } from './dto/role.schema';
import { CreateRoleDto, UpdateRoleDto, RoleMenuAuthDto, RoleDeptAuthDto } from './dto/role.schema';
import { BusinessException } from '../../common/exceptions/biz.exception';

@Injectable()
export class RoleService {
  constructor(private readonly drizzle: DrizzleService) { }

  /**
   * 创建角色并关联菜单、部门
   */
  async create(createRoleDto: CreateRoleDto) {
    const { menuIds, deptIds, ...roleData } = createRoleDto;

    // 事务处理
    return await this.drizzle.db.transaction(async (tx) => {
      // 1. 插入角色
      const result = await tx.insert(roles).values(roleData);
      const roleId = Number(result[0].insertId);

      // 2. 关联菜单
      if (menuIds && menuIds.length > 0) {
        await this.insertRoleMenus(tx, roleId, menuIds);
      }

      // 3. 关联部门
      if (deptIds && deptIds.length > 0) {
        await this.insertRoleDepts(tx, roleId, deptIds);
      }

      return { roleId, ...roleData };
    });
  }

  /**
   * 查询所有角色
   */
  async findAll(query: QueryRoleDto) {
    const { roleName, roleKey, status, pageNum = 1, pageSize = 10 } = query;
    
    // 构建查询条件
    const conditions = [eq(roles.delFlag, '0')];
    
    if (roleName) {
      conditions.push(like(roles.roleName, `%${roleName}%`));
    }
    
    if (roleKey) {
      conditions.push(like(roles.roleKey, `%${roleKey}%`));
    }
    
    if (status !== undefined) {
      conditions.push(eq(roles.status, status));
    }
    
    // 计算分页参数
    const offset = (pageNum - 1) * pageSize;
    
    // 查询总数
    const [countResult] = await this.drizzle.db
      .select({ count: sql<number>`count(*)` })
      .from(roles)
      .where(and(...conditions));
    
    const total = countResult.count;
    
    // 查询分页数据
    const data = await this.drizzle.db
      .select()
      .from(roles)
      .where(and(...conditions))
      .orderBy(roles.roleSort, roles.roleId)
      .limit(pageSize)
      .offset(offset);
    
    return {
      data,
      total,
      pageNum,
      pageSize,
      totalPages: Math.ceil(total / pageSize)
    };
  }

  /**
   * 查询单个角色及其关联的菜单和部门
   */
  async findOne(id: number) {
    const roleInfo = await this.drizzle.db
      .select()
      .from(roles)
      .where(and(
        eq(roles.roleId, id),
        eq(roles.delFlag, '0')
      ));

    if (!roleInfo || roleInfo.length === 0) {
      throw new BusinessException('角色不存在');
    }

    // 获取角色关联的菜单ID
    const menuList = await this.drizzle.db
      .select({
        menuId: roleMenus.menuId
      })
      .from(roleMenus)
      .where(eq(roleMenus.roleId, id));

    // 获取角色关联的部门ID
    const deptList = await this.drizzle.db
      .select({
        deptId: roleDepts.deptId
      })
      .from(roleDepts)
      .where(eq(roleDepts.roleId, id));

    return {
      ...roleInfo[0],
      menuIds: menuList.map(m => m.menuId),
      deptIds: deptList.map(d => d.deptId)
    };
  }

  /**
   * 更新角色及其关联的菜单和部门
   */
  async update(id: number, updateRoleDto: UpdateRoleDto) {
    const { menuIds, deptIds, ...roleData } = updateRoleDto;

    const roleInfo = await this.drizzle.db
      .select()
      .from(roles)
      .where(and(
        eq(roles.roleId, id),
        eq(roles.delFlag, '0')
      ));

    if (!roleInfo || roleInfo.length === 0) {
      throw new BusinessException('角色不存在');
    }

    // 事务处理
    return await this.drizzle.db.transaction(async (tx) => {
      // 1. 更新角色
      await tx.update(roles)
        .set(roleData)
        .where(eq(roles.roleId, id));

      // 2. 更新关联菜单
      if (menuIds !== undefined) {
        // 先删除原有关联
        await tx.delete(roleMenus)
          .where(eq(roleMenus.roleId, id));

        // 再添加新关联
        if (menuIds.length > 0) {
          await this.insertRoleMenus(tx, id, menuIds);
        }
      }

      // 3. 更新关联部门
      if (deptIds !== undefined) {
        // 先删除原有关联
        await tx.delete(roleDepts)
          .where(eq(roleDepts.roleId, id));

        // 再添加新关联
        if (deptIds.length > 0) {
          await this.insertRoleDepts(tx, id, deptIds);
        }
      }

      return { roleId: id, ...roleData };
    });
  }

  /**
   * 删除角色
   */
  async remove(id: number) {
    // 判断是否有用户关联该角色
    const userRoleCount = await this.drizzle.db
      .select({ count: sql<number>`count(*)` })
      .from(userRoles)
      .where(eq(userRoles.roleId, id));

    if (userRoleCount[0].count > 0) {
      throw new BusinessException('该角色存在关联用户，请先删除关联用户');
    }

    // 使用逻辑删除
    return await this.drizzle.db.transaction(async (tx) => {
      // 删除角色
      await tx.update(roles)
        .set({ delFlag: '1' })
        .where(eq(roles.roleId, id));

      // 删除角色菜单关联
      await tx.delete(roleMenus)
        .where(eq(roleMenus.roleId, id));

      // 删除角色部门关联
      await tx.delete(roleDepts)
        .where(eq(roleDepts.roleId, id));

      // 删除角色权限关联
      await tx.delete(rolePermissions)
        .where(eq(rolePermissions.roleId, id));

      return { success: true, message: '删除成功' };
    });
  }

  /**
   * 角色授权菜单
   */
  async authorizeMenu(authDto: RoleMenuAuthDto) {
    const { roleId, menuIds } = authDto;

    // 检查角色是否存在
    const roleInfo = await this.drizzle.db
      .select()
      .from(roles)
      .where(and(
        eq(roles.roleId, roleId),
        eq(roles.delFlag, '0')
      ));

    if (!roleInfo || roleInfo.length === 0) {
      throw new BusinessException('角色不存在');
    }

    return await this.drizzle.db.transaction(async (tx) => {
      // 先删除原有关联
      await tx.delete(roleMenus)
        .where(eq(roleMenus.roleId, roleId));

      // 再添加新关联
      if (menuIds.length > 0) {
        await this.insertRoleMenus(tx, roleId, menuIds);
      }

      return { success: true, message: '授权成功' };
    });
  }

  /**
   * 角色授权部门
   */
  async authorizeDept(authDto: RoleDeptAuthDto) {
    const { roleId, deptIds } = authDto;

    // 检查角色是否存在
    const roleInfo = await this.drizzle.db
      .select()
      .from(roles)
      .where(and(
        eq(roles.roleId, roleId),
        eq(roles.delFlag, '0')
      ));

    if (!roleInfo || roleInfo.length === 0) {
      throw new BusinessException('角色不存在');
    }

    return await this.drizzle.db.transaction(async (tx) => {
      // 先删除原有关联
      await tx.delete(roleDepts)
        .where(eq(roleDepts.roleId, roleId));

      // 再添加新关联
      if (deptIds.length > 0) {
        await this.insertRoleDepts(tx, roleId, deptIds);
      }

      return { success: true, message: '授权成功' };
    });
  }

  /**
   * 按用户ID查询所有角色
   */
  async getRolesByUserId(userId: number) {
    const userRoleList = await this.drizzle.db
      .select({
        roleId: userRoles.roleId
      })
      .from(userRoles)
      .where(eq(userRoles.userId, userId));
    console.log(userId, "userRoleList")
    const roleIds = userRoleList.map((ur) => ur.roleId);

    if (roleIds.length === 0) {
      return [];
    }

    return await this.drizzle.db
      .select()
      .from(roles)
      .where(and(
        inArray(roles.roleId, roleIds),
        eq(roles.delFlag, '0')
      ));
  }

  /**
   * 查询角色对应的权限
   */
  async getRolePermissions(roleId: number) {
    // 查询角色关联的权限ID
    const rolePermList = await this.drizzle.db
      .select({
        permissionId: rolePermissions.permissionId
      })
      .from(rolePermissions)
      .where(eq(rolePermissions.roleId, roleId));

    const permIds = rolePermList.map((rp) => rp.permissionId);

    if (permIds.length === 0) {
      return [];
    }

    // 查询权限详情
    return await this.drizzle.db
      .select()
      .from(rolePermissions)
      .where(inArray(rolePermissions.permissionId, permIds));
  }

  // 辅助方法：批量插入角色-菜单关联
  private async insertRoleMenus(tx: any, roleId: number, menuIds: number[]) {
    const values = menuIds.map(menuId => ({
      roleId,
      menuId
    }));
    await tx.insert(roleMenus).values(values);
  }

  // 辅助方法：批量插入角色-部门关联
  private async insertRoleDepts(tx: any, roleId: number, deptIds: number[]) {
    const values = deptIds.map(deptId => ({
      roleId,
      deptId
    }));
    await tx.insert(roleDepts).values(values);
  }
}